/*
 * 1.00 2012/10/18
 *
 * Copyright (c) 2012 Motch_bs
 * All rights reserved.
 *
 * このソフトウェアは，Motch_bsに所有される機密情報である。
 * これらの機密情報を漏洩してはならず，Motch_bs の意図する
 * 認可の元においてこれを使用すべし。
 */
package jp.co.ufp.voicetch.base.audio;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.util.Log;

/**
 * @author Motch_bs
 * 
 */
public class Player {

    /** ピッチシフト（無効） */
    public static final int MODE_NORMAL = 0;

    /** ピッチシフト（Cライブラリ） */
    public static final int MODE_NATIVE = 1;

    /** ピッチシフト（Java） */
    public static final int MODE_JAVA = 2;

    /** WAB再生 */
    public static final int MODE_WAV = 4;

    /** 保存ファイル */
    public File file;

    /** 周波数 */
    private int frequency = 8000;

    /** チャンネル設定 */
    private int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;

    /** エンコーディング */
    private int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;

    /** 変換クラス */
    private Converter converter = new Converter();

    /**
     * コンストラクタ
     * 
     * @param file
     */
    public Player(File pFile) {
	super();
	this.file = pFile;
    }

    /**
     * 周波数の取得
     * 
     * @return frequency
     */
    public int getFrequency() {
	return frequency;
    }

    /**
     * 周波数の設定
     * 
     * @param frequency
     */
    public void setFrequency(
	int frequency) {
	this.frequency = frequency;
    }

    /**
     * チャンネルの取得
     * 
     * @return channelConfiguration
     */
    public int getChannelConfiguration() {
	return channelConfiguration;
    }

    /**
     * チャンネルの設定
     * 
     * @param channelConfiguration
     */
    public void setChannelConfiguration(
	int channelConfiguration) {
	this.channelConfiguration = channelConfiguration;
    }

    /**
     * エンコーディングの取得
     * 
     * @return audioEncoding
     */
    public int getAudioEncoding() {
	return audioEncoding;
    }

    /**
     * エンコーディングの設定
     * 
     * @param audioEncoding
     */
    public void setAudioEncoding(
	int audioEncoding) {
	this.audioEncoding = audioEncoding;
    }

    short[] buf;
    SinOsc sinosc;
    AudioTrack audioTrack;

    /**
     * 再生
     */
    public void play(
	int mode) {
	// オーディオの保存領域の長さを取得する。
	// (ファイルには、16bitつまりshor型が2バイトある）
	// オーディオを録音した保存領域のshort型の配列を生成する。
	int musicLength = (int) (file.length() / 2);
	short[] data = new short[musicLength];
	try {
	    // 保存ファイルから入力ストリームを取得する
	    InputStream is = new FileInputStream(file);
	    BufferedInputStream bis = new BufferedInputStream(is);
	    DataInputStream dis = new DataInputStream(bis);
	    // 保存ファイルの音声を配列に読み込む
	    int i = 0;
	    while (dis.available() > 0) {
		// data[musicLength - 1 - i] = dis.readShort();
		data[i] = dis.readShort();
		i++;
	    }
	    dis.close();

	    // 音声録音時と同じパラメータでAudioTrackオブジェクトを生成する。
	    audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
		    frequency,
		    channelConfiguration,
		    audioEncoding,
		    musicLength,
		    AudioTrack.MODE_STREAM);
	    audioTrack.setNotificationMarkerPosition(data.length);
	    //buf = data;
	    // 所得したバッファーサイズごとに通知させる。
	    //audioTrack.setPositionNotificationPeriod(bufferSize);
	    // audioTrack.setPlaybackPositionUpdateListener(
	    // new AudioTrack.OnPlaybackPositionUpdateListener() {
	    // public void onMarkerReached(
	    // AudioTrack track) {
	    // }
	    //
	    // // 通知があるごとに実行される。
	    // public void onPeriodicNotification(
	    // AudioTrack track) {
	    // sndOut(buf, sinosc,musicLength);
	    // }
	    // }
	    // );
	    sinosc = new SinOsc(80, 1,frequency);
	    // // C++で変換
	    // if (mode == MODE_NATIVE) {
	    // data = converter.pitchShift_cpp(data);
	    // }
	    // // Javaで変換
	    // else if (mode == MODE_JAVA) {
	    // data = converter.pitchShift_java(data, frequency);
	    // }
	    //
	    // // ***************************************
	    // // Wavで再生
	    // if (mode == MODE_WAV) {
	    // // 再生開始
	    // audioTrack.write(data, 44, data.length - 44);
	    // // byteサイズでなくshortサイズで
	    // audioTrack.setNotificationMarkerPosition((data.length - 44) / 2);
	    // audioTrack.play();
	    // }
	    // else {
	    // // 再生開始
	    // audioTrack.play();
	    // audioTrack.write(data, 0, musicLength);
	    // }
	    audioTrack.play();
	    sndOut(data, sinosc, musicLength);

	}
	catch (FileNotFoundException e) {
	    Log.e("AudioTrack", "Playback Failed");
	    e.printStackTrace();
	}
	catch (IOException e) {
	    Log.e("AudioTrack", "Playback Failed");
	    e.printStackTrace();
	}

    }


    void sndOut(
	short data[], SinOsc input, int len) {
	for (int i = 0; i < data.length; i++) {
	    data[i] = (short) (Short.MAX_VALUE * input.updata());
	}
	audioTrack.write(data, 0, data.length);
    }

    /**
     * 再生
     */
    public void play_20121031(
	int mode) {
	// オーディオの保存領域の長さを取得する。
	// (ファイルには、16bitつまりshor型が2バイトある）
	// オーディオを録音した保存領域のshort型の配列を生成する。
	int musicLength = (int) (file.length() / 2);
	short[] data = new short[musicLength];
	try {
	    // 保存ファイルから入力ストリームを取得する
	    InputStream is = new FileInputStream(file);
	    BufferedInputStream bis = new BufferedInputStream(is);
	    DataInputStream dis = new DataInputStream(bis);
	    // 保存ファイルの音声を配列に読み込む
	    int i = 0;
	    while (dis.available() > 0) {
		// data[musicLength - 1 - i] = dis.readShort();
		data[i] = dis.readShort();
		i++;
	    }
	    dis.close();
	    // 音声録音時と同じパラメータでAudioTrackオブジェクトを生成する。
	    AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
		    frequency,
		    channelConfiguration,
		    audioEncoding,
		    musicLength,
		    AudioTrack.MODE_STREAM);
	    //
	    audioTrack.setNotificationMarkerPosition(data.length);

	    // C++で変換
	    if (mode == MODE_NATIVE) {
		data = converter.pitchShift_cpp(data);
	    }
	    // Javaで変換
	    else if (mode == MODE_JAVA) {
		data = converter.pitchShift_java(data, frequency);
	    }

	    // ***************************************
	    // Wavで再生
	    if (mode == MODE_WAV) {
		// 再生開始
		audioTrack.write(data, 44, data.length - 44);
		// byteサイズでなくshortサイズで
		audioTrack.setNotificationMarkerPosition((data.length - 44) / 2);
		audioTrack.play();
	    }
	    else {
		// 再生開始
		audioTrack.play();
		audioTrack.write(data, 0, musicLength);
	    }

	}
	catch (FileNotFoundException e) {
	    Log.e("AudioTrack", "Playback Failed");
	    e.printStackTrace();
	}
	catch (IOException e) {
	    Log.e("AudioTrack", "Playback Failed");
	    e.printStackTrace();
	}

    }

}
